﻿using CodeBuilderForVS2022.Entity;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Task = System.Threading.Tasks.Task;

namespace CodeBuilderForVS2022
{

    /// <summary>
    /// Command handler
    /// </summary>
    internal sealed class DeleteCommand
    {
        public static DTE2 _dte;

        private static string baseDic;

        /// <summary>
        /// Command ID.
        /// </summary>
        public const int CommandId = 256;

        /// <summary>
        /// Command menu group (command set GUID).
        /// </summary>
        public static readonly Guid CommandSet = new Guid("d5b3a474-ec74-48a5-a778-4b4e97f54c28");

        /// <summary>
        /// VS Package that provides this command, not null.
        /// </summary>
        private readonly AsyncPackage package;

        /// <summary>
        /// Initializes a new instance of the <see cref="DeleteCommand"/> class.
        /// Adds our command handlers for menu (commands must exist in the command table file)
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        /// <param name="commandService">Command service to add command to, not null.</param>
        private DeleteCommand(AsyncPackage package, OleMenuCommandService commandService)
        {
            this.package = package ?? throw new ArgumentNullException(nameof(package));
            commandService = commandService ?? throw new ArgumentNullException(nameof(commandService));

            var menuCommandID = new CommandID(CommandSet, CommandId);
            var menuItem = new MenuCommand(this.Execute, menuCommandID);
            commandService.AddCommand(menuItem);
        }

        /// <summary>
        /// Gets the instance of the command.
        /// </summary>
        public static DeleteCommand Instance
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the service provider from the owner package.
        /// </summary>
        private Microsoft.VisualStudio.Shell.IAsyncServiceProvider ServiceProvider
        {
            get
            {
                return this.package;
            }
        }

        /// <summary>
        /// Initializes the singleton instance of the command.
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        public static async Task InitializeAsync(AsyncPackage package, DTE2 dte)
        {
            // Switch to the main thread - the call to AddCommand in DeleteCommand's constructor requires
            // the UI thread.
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
            _dte = dte;
            OleMenuCommandService commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
            Instance = new DeleteCommand(package, commandService);
        }

        /// <summary>
        /// This function is the callback used to execute the command when the menu item is clicked.
        /// See the constructor to see how the menu item is associated with this function using
        /// OleMenuCommandService service and MenuCommand class.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event args.</param>
        private void Execute(object sender, EventArgs e)
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            ////加载动画
            LoadingForm loadingForm = new LoadingForm();
            loadingForm.MaxCount = 9;
            loadingForm.Show();
            try
            {
                if (_dte.SelectedItems.Count == 1)
                {
                    EntityHelper entityHelper = new EntityHelper(baseDic, _dte);
                    SelectedItem selectedItem = _dte.SelectedItems.Item(1);
                    ProjectItem selectProjectItem = selectedItem.ProjectItem;
                    //获取当前点击的类所在的项目
                    Project entityProject = selectProjectItem.ContainingProject;

                    //api目录
                    baseDic = entityHelper.GetApiDir(entityProject);

                    ////当前类在当前项目中的目录结构
                    string dirPath = entityHelper.GetSelectFileDirPath(entityProject, selectProjectItem);
                    //当前类命名空间
                    string namespaceStr = selectProjectItem.FileCodeModel.CodeElements.OfType<CodeNamespace>().First().FullName;
                    //当前项目根命名空间
                    string applicationStr = "";
                    if (!string.IsNullOrEmpty(namespaceStr))
                    {
                        applicationStr = namespaceStr.Substring(0, namespaceStr.IndexOf("."));
                    }
                    //当前类
                    CodeClass codeClass = entityHelper.GetClass(selectProjectItem.FileCodeModel.CodeElements);
                    //当前项目类名
                    string className = codeClass.Name;
                    string cnName = codeClass.DocComment.Replace("<doc>", "").Replace("<summary>", "").Replace("</doc>", "").Replace("</summary>", "").Replace("\r\n", "");


                    #region 错误提示
                    if (!ConfigHelper.IsFlyadminApi(baseDic))
                    {
                        loadingForm.ShowError("本代码生成器只适用于FlyAdmin.WebApi");
                        return;
                    }
                    if (!ConfigHelper.IsDataTable(baseDic, namespaceStr))
                    {
                        loadingForm.ShowError("请选择需要删除的数据表实体类");
                        return;
                    }
                    #endregion
                    loadingForm.ShowLoading("正在删除Input", 1);
                    //生成DTO
                    var inputProjectItem = entityProject.ProjectItems.Item("Input").ProjectItems.Item(className);
                    if (inputProjectItem != null)
                    {
                        inputProjectItem.Delete();
                    }
                    loadingForm.ShowLoading("正在删除Output", 2);

                    var outputProjectItem = entityProject.ProjectItems.Item("Output").ProjectItems.Item(className);
                    if (outputProjectItem != null)
                    {
                        outputProjectItem.Delete();
                    }

                    loadingForm.ShowLoading("正在删除数据访问层", 3);

                    IEnumerable<Project> projects = _dte.Solution.Projects.OfType<Project>();
                    Project projectIDAL = projects.FirstOrDefault(x => x.Name == $"{applicationStr}.IDAL");
                    var itemIDAL = projectIDAL.ProjectItems.Item($"I{className}DAL.cs");
                    if (itemIDAL != null)
                    {
                        itemIDAL.Delete();
                    }

                    loadingForm.ShowLoading("正在删除数据访问层", 4);
                    Project projectDAL = projects.FirstOrDefault(x => x.Name == $"{applicationStr}.DAL");
                    var itemDAL = projectDAL.ProjectItems.Item($"{className}DAL.cs");
                    if (itemDAL != null)
                    {
                        itemDAL.Delete();
                    }

                    loadingForm.ShowLoading("正在删除应用层", 5);

                    Project projectIApplication = projects.FirstOrDefault(x => x.Name == $"{applicationStr}.IApplication");
                    var itemIApplication = projectIApplication.ProjectItems.Item($"I{className}Application.cs");
                    if (itemIApplication != null)
                    {
                        itemIApplication.Delete();
                    }

                    loadingForm.ShowLoading("正在删除应用层", 6);
                    Project projectApplication = projects.FirstOrDefault(x => x.Name == $"{applicationStr}.Application");
                    var itemApplication = projectApplication.ProjectItems.Item($"{className}Application.cs");
                    if (itemApplication != null)
                    {
                        itemApplication.Delete();
                    }

                    loadingForm.ShowLoading("正在删除接口层", 7);
                    Project projectApi = projects.FirstOrDefault(x => x.Name == $"{applicationStr}.WebApi");
                    ProjectItem controllers = projectApi.ProjectItems.Item("Controllers");
                    var itemApi = controllers.ProjectItems.Item($"{className}Controller.cs");
                    if (itemApi != null)
                    {
                        itemApi.Delete();
                    }

                    loadingForm.ShowLoading($"正在删除Mapper文件", 8);
                    entityHelper.DeleteMapper(entityProject, className, cnName);

                    loadingForm.ShowLoading($"正在删除GlobalUsing文件", 9);
                    entityHelper.DeleteGlobalUsing(applicationStr, className);
                    loadingForm.ShowLoading($"代码删除完毕！", -1);
                }
                else
                {
                    loadingForm.ShowError("请选择需要删除的数据表实体类");
                }
            }
            catch (Exception ex)
            {
                loadingForm.ShowError(ex.Message);
            }
        }
    }
}
